﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RemoteDesktopLib
{
    public static class Utils
    {
        public static Guid Id = Guid.NewGuid();

        /*
         * Function: PackScreenCaptureData
         * Description: hàm đóng gói dữ liệu từ Image của màn hình thành mảng byte
         * Params:
         *  image: ảnh cần đóng gói
         *  bounds: Rectangle của box thay đổi sẽ đóng gói
         */
        public static byte[] PackScreenCaptureData(Image image, Rectangle bounds)
        {
            //ID
            byte[] idData = Id.ToByteArray();

            //Mảng byte thông tin hình ảnh sẽ đóng gói
            //Ảnh sẽ được chuyển định dạng sang jpeg trước khi đóng gói
            byte[] imgData;
            using (MemoryStream ms = new MemoryStream())
            {
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                imgData = ms.ToArray();
            }

            //Các mảng byte chứa thông tin các góc của bounds
            byte[] topData = BitConverter.GetBytes(bounds.Top);
            byte[] botData = BitConverter.GetBytes(bounds.Bottom);
            byte[] leftData = BitConverter.GetBytes(bounds.Left);
            byte[] rightData = BitConverter.GetBytes(bounds.Right);

            //Nối các mảng byte trên lại thành một mảng byte duy nhất
            int sizeOfInt = topData.Length;
            byte[] result = new byte[imgData.Length + 4 * sizeOfInt + idData.Length];
            Array.Copy(topData, 0, result, 0, topData.Length);
            Array.Copy(botData, 0, result, sizeOfInt, botData.Length);
            Array.Copy(leftData, 0, result, 2 * sizeOfInt, leftData.Length);
            Array.Copy(rightData, 0, result, 3 * sizeOfInt, rightData.Length);
            Array.Copy(imgData, 0, result, 4 * sizeOfInt, imgData.Length);
            Array.Copy(idData, 0, result, 4 * sizeOfInt + imgData.Length, idData.Length);

            return result;
        }

        /*
         * Function: UnpackScreenCaptureData
         * Description: hàm giải nén mảng byte thành ảnh
         * Params:
         *  data: mảng byte cần giải nén
         *  image: ảnh kết quả
         *  bounds: box kết quả
         *  id: id kết quả
         */
        public static void UnpackScreenCaptureData(byte[] data, out Image image, out Rectangle bounds, out Guid id)
        {
            // Tạo các mảng byte để chứa dữ liệu giải nén
            const int numBytesInInt = sizeof(int);
            int idLength = Guid.NewGuid().ToByteArray().Length;
            int imgLength = data.Length - 4 * numBytesInInt - idLength;
            byte[] topPosData = new byte[numBytesInInt];
            byte[] botPosData = new byte[numBytesInInt];
            byte[] leftPosData = new byte[numBytesInInt];
            byte[] rightPosData = new byte[numBytesInInt];
            byte[] imgData = new byte[imgLength];
            byte[] idData = new byte[idLength];

            // đẩy dữ liệu vào các mảng byte
            Array.Copy(data, 0, topPosData, 0, numBytesInInt);
            Array.Copy(data, numBytesInInt, botPosData, 0, numBytesInInt);
            Array.Copy(data, 2 * numBytesInInt, leftPosData, 0, numBytesInInt);
            Array.Copy(data, 3 * numBytesInInt, rightPosData, 0, numBytesInInt);
            Array.Copy(data, 4 * numBytesInInt, imgData, 0, imgLength);
            Array.Copy(data, 4 * numBytesInInt + imgLength, idData, 0, idLength);

            // Tạo ảnh dựa vào mảng byte ảnh
            MemoryStream ms = new MemoryStream(imgData, 0, imgData.Length);
            ms.Write(imgData, 0, imgData.Length);
            image = Image.FromStream(ms, true);

            //Dựng lại rectangle dựa vào mảng byte 
            int top = BitConverter.ToInt32(topPosData, 0);
            int bot = BitConverter.ToInt32(botPosData, 0);
            int left = BitConverter.ToInt32(leftPosData, 0);
            int right = BitConverter.ToInt32(rightPosData, 0);
            int width = right - left + 1;
            int height = bot - top + 1;
            bounds = new Rectangle(left, top, width, height);

            // Tạo lại GUID
            //
            id = new Guid(idData);
        }


        /*
         * Function: UpdateScreen
         * Description: hàm cập nhật lại màn hình khi bị thay đổi
         * Params:
         *  screen: Image ban đầu
         *  newPartialScreen: phần image bị thay đổi
         *  boundingBox: phần box thay đổi
         */
        public static void UpdateScreen(ref Image screen, Image newPartialScreen, Rectangle boundingBox)
        {
            if (screen == null)
            {
                screen = new Bitmap(boundingBox.Width, boundingBox.Height);
            }

            // Vẽ phần image thay đổi vào image ban đầu
            Graphics g = null;
            try
            {
                lock (screen)
                {
                    g = Graphics.FromImage(screen);
                    g.DrawImage(newPartialScreen, boundingBox);
                    g.Flush();
                }
            }
            catch
            {
                // Do something with this info.
            }
            finally
            {
                if (g != null) g.Dispose();
            }
        }


        /*
         * Function: UpdateScreen
         * Description: hàm cập nhật lại màn hình khi bị thay đổi
         * Params:
         *  screen: Image ban đầu
         *  data: mảng byte chứa thông tin thay đổi
         */
        public static void UpdateScreen(ref Image screen, byte[] data)
        {
            // Unpack the data bytes.
            //
            Image partial;
            Rectangle bounds;
            Guid id;
            UnpackScreenCaptureData(data, out partial, out bounds, out id);

            // Update the current screen.
            //
            UpdateScreen(ref screen, partial, bounds);
        }


    }

    public static class Logger
    {
        public static void Error(string message, string module)
        {
            WriteEntry(message, "error", module);
        }

        public static void Error(Exception ex, string module)
        {
            WriteEntry(ex.Message, "error", module);
        }

        public static void Warning(string message, string module)
        {
            WriteEntry(message, "warning", module);
        }

        public static void Info(string message, string module)
        {
            WriteEntry(message, "info", module);
        }


        private static void WriteEntry(string message, string type, string module)
        {
            Trace.WriteLine(
                    string.Format("{0},{1},{2},{3}",
                                  DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                                  type,
                                  module,
                                  message));
        }
    }

}
